package com.example.voucher.bo;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;

import org.apache.commons.beanutils.MethodUtils;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.example.voucher.config.bo.FieldReducingConfigBO;
import com.example.voucher.contract.VoucherItemAccessor;
import com.google.common.collect.Maps;

public class VoucherItemAccessorHelper {

    private static final Logger LOGGER = LoggerFactory.getLogger(VoucherItemAccessorHelper.class);

    private static final String DEFAULT_STATIC_CONSTRUCTOR_NAME = "of";

    private VoucherItemAccessorHelper() {}
    
    /**
     * 按照指定的key全类名+配置分组汇总List<VoucherItemAccessor>
     * 
     * @param srcList
     * @param keyClassName
     * @param reducingConfigList
     * @return
     */
    public static Map<Object, VoucherItemAccessor> groupingAndReducingVoucherItemAccessor(
        final List<VoucherItemAccessor> srcList, 
        final String keyClassName,
        final List<FieldReducingConfigBO> reducingConfigList) {
        Map<Object, List<VoucherItemAccessor>> srcMap = srcList.stream()
            .collect(Collectors.groupingBy(t -> getKeyInstanceFormVoucherItemAccessor(t, keyClassName)));
        return combinerVoucherItemAccessor(srcMap, reducingConfigList);
    }

    /**
     * 从VoucherItemAccessor获取全类名为keyClassName的实例
     * 
     * @param accessor
     * @param keyClassName
     * @return
     */
    public static Object getKeyInstanceFormVoucherItemAccessor(final VoucherItemAccessor accessor,
        final String keyClassName) {
        final Class<?> clazz;
        try {
            clazz = Class.forName(keyClassName);
        } catch (Exception e) {
            LOGGER.error(String.format("入参有误，找不到分组类{%s}", keyClassName), e);
            throw new RuntimeException(e);
        }
        Method method =
            MethodUtils.getAccessibleMethod(clazz, DEFAULT_STATIC_CONSTRUCTOR_NAME, VoucherItemAccessor.class);
        if (method == null || !Modifier.isStatic(method.getModifiers())) {
            LOGGER.error("在分组类K{}里找不到入参为VoucherItemAccessor返回值为K的静态方法{}", keyClassName,
                DEFAULT_STATIC_CONSTRUCTOR_NAME);
            throw new RuntimeException(String.format("在分组类K{%s}里找不到入参为VoucherItemAccessor返回值为K的静态方法{%s}", keyClassName,
                DEFAULT_STATIC_CONSTRUCTOR_NAME));
        }

        Object key = null;
        try {
            key = MethodUtils.invokeStaticMethod(clazz, DEFAULT_STATIC_CONSTRUCTOR_NAME, accessor);
        } catch (Exception e) {
            LOGGER.error(String.format("获取VoucherItemAccessor的分组类K{%s}发生异常", keyClassName), e);
            throw new RuntimeException(String.format("获取VoucherItemAccessor的分组类K{%s}发生异常", keyClassName), e);
        }
        return key;
    }

    private static <K> Map<K, VoucherItemAccessor> combinerVoucherItemAccessor(
        final Map<K, List<VoucherItemAccessor>> srcMap, 
        final List<FieldReducingConfigBO> reducingConfig) {
        Map<K, VoucherItemAccessor> map = Maps.newHashMap();
        for (Entry<K, List<VoucherItemAccessor>> entry : srcMap.entrySet()) {
            K key = entry.getKey();
            List<VoucherItemAccessor> accessorList = entry.getValue();
            if (CollectionUtils.isNotEmpty(accessorList)) {
                VoucherItemAccessor value = accessorList.stream().reduce(VoucherItemAccessor.combinerBinaryOperator(reducingConfig)).get();
                map.put(key, value);
            }else {
                map.put(key, null);
            }
        }
        return map;
    }

}
